package com.zmn.oms.third.core.interfaces.impl;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.notifylog.OrderNotifyLogBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.common.exception.chan.ChannelFacadeException;
import com.zmn.oms.common.exception.chan.DuplicateOrderClueException;
import com.zmn.oms.model.dto.order.proxy.OrderLogDTO;
import com.zmn.oms.model.entity.chan.FacadeMessage;
import com.zmn.oms.model.entity.chan.FacadeMessageEvent;
import com.zmn.oms.model.entity.chan.OrderClue;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.notifylog.OrderNotifyLog;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkLogChange;
import com.zmn.oms.services.interfaces.chan.FacadeSyncService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.core.interfaces.ChannelFacadeBService;
import com.zmn.oms.third.pinduoduo.PinDuoDuoConsts;
import com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoResponse;
import com.zmn.oms.third.zhimi.ZhimiConsts;
import com.zmn.oms.zmn.aop.OrderWorkLogUtils;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeMessageBService;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeMessageEventErrorBService;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeOrderClueBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;

/**
 * 类描述：
 *
 * @author lhl
 * @date 2020/12/31 18:32
 */
@Slf4j
@Service("channelFacadeBService")
public class ChannelFacadeBServiceImpl implements ChannelFacadeBService {

    @Autowired
    private FacadeOrderClueBService facadeOrderClueBService;
    @Autowired
    private FacadeSyncService facadeSyncService;
    @Autowired
    private FacadeMessageEventErrorBService facadeMessageEventErrorBService;
    @Autowired
    private FacadeMessageBService facadeMessageBServices;
    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderLogBService orderLogBService;
    @Autowired
    private OrderNotifyLogBService orderNotifyLogBService;

    /**
     * 新建新单线索
     * @param event 渠道门户枚举
     * @param outerId 渠道订单ID
     * @param generateFacadeOrderId 是否生成需要返回给渠道方的啄木鸟订单ID，如果为 true，生成的ID将在方法调用结束后保存在 orderClue 参数对象的 facadeOrderId 字段中
     * @return
     * @throws DuplicateOrderClueException 当判定该线索为重复收到时被抛出，判定条件为：channelFacade 和 outerId 组合值是否唯一
     * @throws ChannelFacadeException 当保存失败时被抛出
     */
    @Override
    public OrderClue createOrderClue(FacadeMessageEvent event,
                                     String outerId,
                                     boolean generateFacadeOrderId) throws DuplicateOrderClueException, ChannelFacadeException {

        return this.createOrderClue(event, outerId, generateFacadeOrderId, null, null);
    }


    /**
     * 新建新单线索
     * @param event
     * @param outerId 渠道订单ID
     * @param generateFacadeOrderId 是否生成需要返回给渠道方的啄木鸟订单ID，如果为 true，生成的ID将在方法调用结束后保存在 orderClue 参数对象的 facadeOrderId 字段中
     * @param extOuterId1 第一外部扩展订单号
     * @param extOuterId2 第二外部扩展订单号
     * @return
     * @throws DuplicateOrderClueException 当判定该线索为重复收到时被抛出，判定条件为：channelFacade 和 outerId 组合值是否唯一
     * @throws ChannelFacadeException 当保存失败时被抛出
     */
    @Override
    public OrderClue createOrderClue(FacadeMessageEvent event,
                                  String outerId,
                                  boolean generateFacadeOrderId,
                                  String extOuterId1,
                                  String extOuterId2) throws DuplicateOrderClueException, ChannelFacadeException {

        OrderClue orderClue = new OrderClue();
        orderClue.setFacadeId(event.getFacadeId());
        orderClue.setChannelId(event.getChannelId());
        orderClue.setOuterId(outerId);
        orderClue.setExtOuterId1(extOuterId1);
        orderClue.setExtOuterId2(extOuterId2);

        FacadeMessage facadeMessage = new FacadeMessage();
        facadeMessage.setFacadeId(event.getFacadeId());
        facadeMessage.setEventTag(event.getTag());
        facadeMessage.setEventFun(event.getFun());
        facadeMessage.setContent(event.getContent());

        facadeOrderClueBService.saveOrderClue(orderClue, facadeMessage, generateFacadeOrderId);

        return orderClue;
    }

    /**
     * 获取对应的订单线索
     * @param orderClueId 订单线索主键ID
     * @return 对应的订单线索，如果没找到，返回null
     */
    @Override
    public OrderClue findOrderClueByOrderClueId(Long orderClueId) {
        return facadeOrderClueBService.findOrderClueByKey(orderClueId);
    }

    /**
     * 收到订单的业务消息，保存消息并获取对应的订单线索
     * @param event 该对象的 facadeId、tag、content 字段不能为null
     * @param outerId 渠道订单号
     * @param channelId 渠道订单号
     * @return 对应的订单线索
     * @throws ChannelFacadeException 当未找到对应的订单线索或保存消息失败时被抛出
     */
    @Override
    public OrderClue receiveOrderBizMessage(FacadeMessageEvent event, String outerId, Integer channelId)
            throws ChannelFacadeException {

        FacadeMessage facadeMessage = new FacadeMessage();
        facadeMessage.setFacadeId(event.getFacadeId());
        facadeMessage.setEventTag(event.getTag());
        facadeMessage.setEventFun(event.getFun());
        facadeMessage.setContent(event.getContent());
        return facadeOrderClueBService.saveOrderBizMessage(facadeMessage, outerId, channelId);
    }

    /**
     * 收到非订单消息，保存消息
     * @param event
     * @throws ChannelFacadeException 当保存消息失败时被抛出
     */
    @Override
    public void receiveNonOrderMessage(FacadeMessageEvent event) throws ChannelFacadeException {

        /* TODO -lhl 保存非订单消息，保存在哪儿？
        FacadeMessage facadeMessage = new FacadeMessage();
        facadeMessage.setFacadeId(facadeId);
        facadeMessage.setContent(content);
        facadeMessageBServices.save(facadeMessage);
        */

    }


    /**
     * 发送渠道门户消息事件
     * @param facadeMessageEvent
     */
    @Override
    public void sendFacadeMessageEvent(FacadeMessageEvent facadeMessageEvent) {
        facadeSyncService.sendFacadeMessageEventSync(facadeMessageEvent);
    }

    /**
     * 保存渠道门户消息事件错误
     * @param facadeMessageEvent
     * @param errorMsg
     */
    @Override
    public void saveFacadeMessageEventError(FacadeMessageEvent facadeMessageEvent, String errorMsg) {
        facadeMessageEventErrorBService.saveFacadeMessageEventError(facadeMessageEvent, errorMsg);
    }

    /**
     * 保存自定义订单操作日志
     * @param orderLogDTO
     */
    @Override
    public void saveCustomOrderLog(OrderLogDTO orderLogDTO) {
        if (orderLogDTO == null || orderLogDTO.getOrderId() == null) {
            return;
        }
        if (orderLogDTO.getType() == null) {
            orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
        }
        if (orderLogDTO.getOperatorType() == null) {
            orderLogDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
            orderLogDTO.setOperator("渠道");
            orderLogDTO.setOperatorId((long)ZhimiConsts.CHANNEL_ID);
        }
        Long orderId = orderLogDTO.getOrderId();
        Long workId = Optional.ofNullable(orderLogDTO.getWorkId()).orElse(orderId);
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);

        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(orderId);
        orderLog.setWorkId(workId);
        orderLog.setType(orderLogDTO.getType());
        orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(orderLogDTO.getType()));
        orderLog.setBeforeStatus(orderWork.getStatus());
        orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setBeforeResultStatus(orderWork.getResultStatus());
        orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        orderLog.setAfterStatus(orderWork.getStatus());
        orderLog.setAfterStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setAfterResultStatus(orderWork.getResultStatus());
        orderLog.setAfterResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        OrderWorkLogUtils.processOrderLogOperater(orderLog, orderLogDTO);

        StringBuilder sb = new StringBuilder();

        if (StringUtil.isNotBlank(orderLogDTO.getOperatorRemark())) {
            sb.append(orderLogDTO.getOperatorRemark());
        }

        if (StringUtil.isNotBlank(orderLogDTO.getOperatorLogRemark())) {
            sb.append(orderLogDTO.getOperatorLogRemark());
        }

        orderLog.setContent(sb.toString());
        orderLogBService.save(orderLog);
    }

    /**
     * 保存状态同步结果信息
     * @param orderWorkLogChange
     * @param orderStatus
     * @param result
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void saveSyncResult(OrderWorkLogChange orderWorkLogChange, int orderStatus, PinDuoDuoResponse result) {
        if (Objects.isNull(result) || Objects.isNull(orderWorkLogChange)) {
            return;
        }

        OrderNotifyLog orderNotifyLog = new OrderNotifyLog();
        orderNotifyLog.setMqMsgKey(orderWorkLogChange.getMqMsgKey());
        orderNotifyLog.setOrderId(orderWorkLogChange.getOrderId());
        orderNotifyLog.setChannelId(orderWorkLogChange.getChannelId());
        orderNotifyLog.setOrderStatus(orderWorkLogChange.getStatus());
        orderNotifyLog.setOrderResultStatus(orderWorkLogChange.getResultStatus());
        orderNotifyLog.setNotifyStatus(String.valueOf(orderStatus));
        orderNotifyLog.setType(OrderConsts.ORDER_NOTIFY_TYPE_CHANGE);
        orderNotifyLog.setNotifyTime(DateUtil.getNow());
        orderNotifyLog.setNotifyResultMsg(String.format("[%s]-%s",
                OrderStatusConsts.getOrderStatusName(orderStatus), result.getErrorMsg()));

        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setStatus(result.getErrorCode() == PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS ? StatusConsts.STATUS_SUCCESS : StatusConsts.STATUS_ERROR);
        resultDTO.setData(orderNotifyLog);

        orderNotifyLogBService.saveNotifyLog(resultDTO);
    }
}
